namespace AnalyStock.DataManage;
internal enum UpdateDataType
{
    Insert, Modify, ReWrite
}
internal class CommDataHelper<T> where T : class, new()
{
    /// <summary>
    ///     获取在线数据，使用反射处理扩展在线数据类，较直接new实例牺牲了一些性能
    /// </summary>
    /// <param name="args"> params:stockCode,StartDate,EndDate,TradeDate</param>
    /// <returns></returns>
    internal static async Task<IList<T>> GetDataOnlineAsync(params string[] args)
    {
        IDownDataTemplate<T> iDownData =
             Activator.CreateInstance(GetQueryClass()) as DownDataTemplate<T>;
        return await iDownData.DownloadOnlineAsync(args);
    }
    /// <summary>
    ///     获取在库数据,使用反射处理扩展数据查询类，较直接new实例牺牲了一些性能
    /// </summary>
    /// <param name="args">params:stockCode,StartDate,EndDate,TradeDate</param>
    /// <returns></returns>
    internal static async Task<IList<T>> GetDataOnDbSetAsync(params string[] args)
    {
        IDbTemplate<T> idbTable =
             Activator.CreateInstance(GetQueryClass(false)) as DbTemplate<T>;
        return await idbTable.QueryDataAsync(args);
    }
    private static Type GetQueryClass(bool isOnline = true)
    {
        var arrayTypeName = typeof(T).FullName.Split(".");
        //添加多态类命名的前缀
        arrayTypeName[^1] = $"{(isOnline ? "DownloadOnline_" : "DbQuery_")}{arrayTypeName.Last()}";
        string classFullName = string.Join(".", arrayTypeName);
        Type t = Type.GetType(classFullName);
        return t switch
        {
            null => throw new Exception($"加载 {classFullName} 类错误!"),
            _ => t
        };
    }

    /// <summary>
    ///     删除在库数据
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    internal static async Task<int> DeleDataOnDbSetAsync(IList<T> list)
    {
        return await new DbTemplate<T>().DeleDataAsync(list);
    }


    /// <summary>
    ///     保存到库文件
    /// </summary>
    /// <param name="list"></param>
    /// <param name="isReWriteOrInsert"></param>
    /// <param name="args">stockCode</param>
    /// <returns></returns>

    //stockCode参数主要是指明数据文件的路径及名称。
    internal static async Task<int> SaveDataToDbSetAsync(IList<T> list, string stockCode = default)
    {
        (UpdateDataType saveType, string code) = typeof(T) switch
        {
            { Name: nameof(Daily) } => (UpdateDataType.Insert, stockCode), //保存插入记录，编码值不能空,需要导向个股库文件
            { Name: nameof(DynamicFinancialIndex) } => (UpdateDataType.Insert, stockCode),
            { Name: nameof(SelectStock) } => (UpdateDataType.Modify, null), //保存修改或插入记录，编码值为空，导向SeleStock文件
            { Name: nameof(Conception) } => (UpdateDataType.Modify, null),
            { Name: nameof(BakDaily) } => (UpdateDataType.ReWrite, null), //保存使用重写覆盖，编码值为空，导向Basic库文件
            { Name: nameof(StockBasic) } => (UpdateDataType.ReWrite, null),
            _ => throw new ArgumentNullException()
        };
        return await new DbTemplate<T>().SaveDataAsync(list, saveType, code);
    }
}

/// <summary>
/// 腾讯在线数据接口扩展处理
/// </summary>
internal static class DownLoadExtensions_Tencent
{

    internal static async Task<IList<MinuteData>> GetMinuteDataOnTencentAsync(this string stockCode)
    {
        var list = new List<MinuteData>();
        //获取分时数据
        var mintueInfor = await CommDataMethod<MinuteOfTencent>
            .GetDataOnlineAsync(stockCode)
            .ConfigureAwait(false);
        if (!mintueInfor.FirstOrDefault()?.Data.Any() ?? true) return list;
        var minuteDatas = mintueInfor.FirstOrDefault().Data;       
        //获取当日及时交易信息
        var daily = await CommDataMethod<DailyOfTencent>
            .GetDataOnlineAsync(stockCode)
            .ConfigureAwait(false);
        var currentDate = mintueInfor.FirstOrDefault().Date;
        var yestClose = daily.FirstOrDefault().YestClose;
        float lastAccumVol = 0.0f;
        //是否新三板
        bool isNEEQ = stockCode.StartsWith("68");
        foreach (var strValue in minuteDatas)
        {
            var item = strValue.Split(" ");
            var currentPrice = item[1].ConvertToFloat();
            var accumVol = item[2].ConvertToFloat();
            var accumAmount = item.Count() > 3
                                ? item[3].ConvertToFloat()
                                : currentPrice * accumVol;
            //新三板传递单位为“股”，其他为"手"，统一转化为"股"
            //新三板传递单位为“股”，其他为"手"，统一转化为"股"
            accumVol = isNEEQ ? accumVol : accumVol * 100.0f;
            list.Add(new MinuteData
            {
                Ts_code = stockCode,
                Date = currentDate,
                Mintue = item[0],
                Price_timely = currentPrice,
                //单位转化为"手"
                Volume = (accumVol - lastAccumVol) / 100.0f,
                Yestclose = yestClose,
                Price_mean = accumVol > 0 ? accumAmount / accumVol : 0
            });
            lastAccumVol = accumVol;
        }
        return list.Take(242).ToList();
    }
    internal static async Task<IList<Daily>> GetCurrentDailyOnlineAsync(this IList<Daily> list)
    {
        if (list.IsNullOrEmpty()) return list;
        var todayTradeInfo = (await CommDataMethod<DailyOfQutoes>
                .GetDataOnlineAsync(list.First().Ts_code)
                .ConfigureAwait(false))
            .FirstOrDefault();
        var currentTime = DateTime.Parse(todayTradeInfo.Time).ToString("yyyyMMdd");
        //如果库里数据不包括当日数据，则追加当日在线数据
        if (currentTime.Equals(list.Last().Trade_date)) return list;
        //停盘
        if (todayTradeInfo.Open == 0 && todayTradeInfo.Volume == 0) return list;
        list.Add(new Daily
        {
            Trade_date = currentTime,
            Ts_code = list[0].Ts_code,
            Open = todayTradeInfo.Open,
            High = todayTradeInfo.High,
            Low = todayTradeInfo.Low,
            Close = todayTradeInfo.Price,
            Pre_close = todayTradeInfo.Yestclose,
            Change = todayTradeInfo.Updown,
            Pct_chg = todayTradeInfo.Percent * 100.0f,
            Vol = todayTradeInfo.Volume / 100.0f,
            Amount = todayTradeInfo.Turnover / 1000.0f,
            Adj_factor = list.Last().Adj_factor
        });
        return list;
    }
    internal static void AddCurrentDailyByMinute(this IList<Daily> dailies, IList<MinuteData> list)
    {
        if (list.IsNullOrEmpty()) return;
        var (maxPrice, minPrice) = list.MaxMinFloat(n => n.Price_timely);
        var _daily = new Daily
        {
            Ts_code = list[0].Ts_code,
            Trade_date = list[0].Date,
            Pre_close = list[0].Yestclose,
            Open = list[0].Price_timely,
            Close = list[list.Count - 1].Price_timely,
            High = maxPrice,
            Low = minPrice,
            Change = ((maxPrice / minPrice) - 1) * 100.0f,
            Pct_chg = ((list[list.Count - 1].Price_timely / list[0].Yestclose) - 1) * 100.0f,
            Vol = list.Sum(n => n.Volume),
            Amount = list.Sum(n => n.Volume * n.Price_mean) / 10.0f
        };
        _daily.Adj_factor = dailies.LastOrDefault().Adj_factor;
        var _datesgap = _daily.Trade_date.ConvertToDate()
                        - dailies.Last().Trade_date.ConvertToDate();
        //如果日期不同才可以追加在线记录
        //交易日之间间隔最多为国庆+周末，12天.平移K线时适当追加记录
        if (_datesgap.Days is > 0 and < 12)
        {
            dailies.Add(_daily);
        }
        if (_datesgap.Days is 0)
        {
            dailies[^1] = _daily;
        }
    }
}